//
// Created by yanhai on 2020/4/29.
//

#include <iostream>
#include <cassert>

using namespace std;

// 特化数据类型表
class Test1 {
public:
    char compute(int x, double y)
    {
        return x;
    }
};

class Test2 {
public:
    double compute(double x, double y)
    {
        return x;
    }
};

// 都有一个compute函数，而且两个函数的逻辑完全相同
// 不同的仅仅是函数参数类型

// 对上面两个类改造，使用类模板
template<typename Arg1, typename Arg2, typename Ret>
class Test {
public:
    Ret compute(Arg1 x, Arg2 y)
    {
        return x;
    }
};
// 缺点，没有很好的复用已经设计好的函数
// 在Test的设计当中，它浸入了Test1和Test2的设计（能设计出Test，说明已经完全知道了Test1和Test2的设计逻辑）

// 最好的设计，应该是：假如已经有了一个函数func(), 我们设计一个函数go(),在go()函数中去调用func()
// 两个类模板规范一个统一的接口
template<typename T>
class TypeTb1 {

};

// 特化模板
template<>
class TypeTb1<Test1> {
public:
    typedef char ret_type;
    typedef int par1_type;
    typedef double par2_type;
};

template<>
class TypeTb1<Test2> {
public:
    typedef double ret_type;
    typedef double par1_type;
    typedef double par2_type;
};

// Test1和Test2的模板
template<typename T>
class TestB {
public:
    typename TypeTb1<T>::ret_type compute(
            typename TypeTb1<T>::par1_type x,
            typename TypeTb1<T>::par2_type y
    )
    {
        return x;
    }
};

void test1()
{
    TestB<Test1> t1;
    assert(t1.compute(65, 100.1) == 'A');
}

// Traits : 类型萃取
// 泛型 ==》 约定代码中的复杂数据类型的基本特征
// 比如 Student Teacher类的指针 pStu, pTeacher
// 要想兼容以上两种指针类型，必须使用 void *pTemp = pStu(pTeacher)
// 缺点：类型不安全的问题：指针天生的不具备向外提供数据类型的能力
// 指针不是类，他就是一个变量，没有办法约束类型
// 想要约束类型：对指针进行模板特化，这样就延伸出符合接口定义的统一类型型别的别名
template<typename T>
class Iterator_1 {
public:
    typedef T value_type;
    typedef value_type *pointer;
    typedef value_type & reference;
};

template<typename T>
class Iterator_2 {
public:
    typedef T value_type;
    typedef value_type *pointer;
    typedef value_type & reference;
};

template <typename T>
struct Traits {

};

template <typename T>
struct Traits<T *> {
    typedef T value_type;
    typedef value_type *pointer;
    typedef value_type &reference;
};

class A {
public:
    void show() {
        cout << "A show function" << endl;
    }
};

void test2()
{
    Iterator_1<int>::value_type t1 = 100;
    cout << t1 << endl;
    Iterator_1<double>::value_type t2 = 6.18;
    cout << t2 << endl;
    Traits<double *>::value_type t3 = 4.44;
    cout << t3 << endl;

    // 我们通过Traits的数据类型信息，可以有效的规范出，类型统一，从而避免类型转换问题
    // 泛型编程的基石
    Iterator_1<A>::pointer p = new A;
    p->show();

    Traits<A *>::pointer p2 = new A;
    p2->show();
}

int main()
{
    test1();
    test2();
    return 0;
}
